package com.sneaker.shower.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sneaker.shower.common.AES;
import com.sneaker.shower.common.BizException;
import com.sneaker.shower.common.ThreadLocalCache;
import com.sneaker.shower.entity.domain.BaseDomain;
import com.sneaker.shower.entity.domain.organization.OrganizationDO;
import com.sneaker.shower.entity.dto.OfflinePayOrgInfoDTO;
import com.sneaker.shower.entity.dto.OrganizationDTO;
import com.sneaker.shower.mapper.OrganizationMapper;
import com.sneaker.shower.mapstruct.OrganizationMapStruct;
import com.sneaker.shower.service.OrganizationService;
import com.sneaker.shower.util.MapUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrganizationServiceImpl extends ServiceImpl<OrganizationMapper, OrganizationDO> implements OrganizationService {

    private final MapUtils mapUtils;

    @Autowired
    public OrganizationServiceImpl(MapUtils mapUtils) {
        this.mapUtils = mapUtils;
    }

    @Override
    public boolean addOrganization(OrganizationDTO dto) {
        OrganizationDO organizationDO = Optional.ofNullable(dto).map(OrganizationMapStruct.INSTANCE::toDo).orElseThrow(() -> new IllegalArgumentException("参数错误"));

        Integer count = baseMapper.selectCount(new LambdaQueryWrapper<OrganizationDO>().eq(OrganizationDO::getName, dto.getName()));
        if (count > 0) {
            throw new IllegalArgumentException("门店名称重复");
        }
        organizationDO.setGuid(IdWorker.getId());
        return baseMapper.insert(organizationDO) == 1;
    }

    @Override
    public boolean delOrganization(String guid, String name) {
        return baseMapper.delete(
                new LambdaQueryWrapper<OrganizationDO>()
                        .eq(StringUtils.isNoneBlank(guid), BaseDomain::getGuid, guid)
                        .eq(StringUtils.isNoneBlank(name), OrganizationDO::getName, name)
        ) > 0;
    }

    @Override
    public boolean modifyOrganization(OrganizationDTO dto) {
        OrganizationDO db = baseMapper.selectOne(
                new LambdaQueryWrapper<OrganizationDO>()
                        .eq(dto.getGuid() != null, OrganizationDO::getGuid, dto.getGuid())
                        .eq(dto.getGuid() == null, OrganizationDO::getGuid, -1)

        );
        if (db == null) {
            db = baseMapper.selectOne(
                    new LambdaQueryWrapper<OrganizationDO>()
                            .eq(StringUtils.isNoneBlank(dto.getName()), OrganizationDO::getName, dto.getName())
                            .eq(!StringUtils.isNoneBlank(dto.getName()), OrganizationDO::getGuid, -1)

            );
        }
        if (db == null) {
            throw new IllegalArgumentException("分店不存在");
        }
        OrganizationDO neo = OrganizationMapStruct.INSTANCE.toDo(dto);
        neo.setGuid(db.getGuid());
        return baseMapper.updateById(neo) == 1;
    }

    @Override
    public List<OrganizationDTO> listOrganization() {
        return baseMapper.selectList(new LambdaQueryWrapper<>()).stream().map(OrganizationMapStruct.INSTANCE::do2DTO).collect(Collectors.toList());
    }

    @Override
    public OrganizationDTO currentOrganization(String longitude, String latitude) {
        if (StringUtils.isEmpty(longitude) || StringUtils.isEmpty(latitude)) {
            return Optional.ofNullable(
                    baseMapper.selectOne(new LambdaQueryWrapper<OrganizationDO>()
                            .eq(OrganizationDO::getType, 1)
                            .eq(OrganizationDO::getIsEnable, true)))
                    .map(OrganizationMapStruct.INSTANCE::do2DTO).orElse(null);
        }
        List<OrganizationDTO> organizationDTOS = listOrganization();
        Optional<OrganizationDTO> first = organizationDTOS.stream()
                .filter(OrganizationDTO::getIsEnable)
                .min(Comparator.comparing((o) -> {
                    BigDecimal latitude1 = o.getLatitude();
                    BigDecimal longitude1 = o.getLongitude();
                    Integer distant = mapUtils.distant(latitude1, longitude1, new BigDecimal(longitude), new BigDecimal(latitude));
                    log.info("用户地址：【{}】，门店【{}】位置【{}】，距离【{}】米", latitude + "," + longitude, o.getName(), latitude1 + "," + longitude1, distant);
                    return distant;
                }));
        return first.orElse(Optional.ofNullable(
                baseMapper.selectOne(new LambdaQueryWrapper<OrganizationDO>()
                        .eq(OrganizationDO::getType, 1)
                        .eq(OrganizationDO::getIsEnable, true)))
                .map(OrganizationMapStruct.INSTANCE::do2DTO).orElse(null));
    }

    @Override
    public Boolean checkStatus() {
        OrganizationDO org = ThreadLocalCache.getOrg();
        if (!org.getIsEnable()) {
            throw new BizException("当前门店暂未开启，敬请期待");
        }
        return true;
    }

    @Override
    public OfflinePayOrgInfoDTO checkQrCode(String encryptStr) {
        try {
            String orgGuidStr = AES.decrypt(new String(Base64Utils.decodeFromString(encryptStr)));
            OrganizationDO org = this.getById(Long.parseLong(orgGuidStr));
            if (org == null) {
                throw new BizException("非门店支付二维码");
            }
            return OfflinePayOrgInfoDTO.builder()
                    .guid(String.valueOf(org.getGuid()))
                    .englishName(org.getEnglishShortName())
                    .name(org.getStoreName())
                    .build();
        } catch (Exception e) {
            throw new BizException("非门店支付二维码");
        }
    }

    @Override
    public OrganizationDTO getMainOrg() {
        return OrganizationMapStruct.INSTANCE.do2DTO(getOne(new LambdaQueryWrapper<OrganizationDO>().eq(OrganizationDO::getType, 1)
                .eq(OrganizationDO::getIsEnable, true)));
    }
}
